
#pragma once

#include <semphr.h>

#include "os_basic_common.hpp"


class Mutex final {
   public:
    Mutex() :
        handle(
#if configSUPPORT_STATIC_ALLOCATION > 0
            xSemaphoreCreateMutexStatic(&buffer)
#else
            xSemaphoreCreateMutex()
#endif
        ) {
    }

    ~Mutex() {
        vSemaphoreDelete(handle);
    }

    explicit Mutex(const Mutex& other) = delete;
    Mutex& operator=(const Mutex& other) = delete;

    void lock() {
        xSemaphoreTake(handle, portMAX_DELAY);
    }

    void unlock() {
        xSemaphoreGive(handle);
    }

    bool tryLock() {
        return xSemaphoreTake(handle, 0) == pdTRUE;
    }

    bool try_lock() {
        return tryLock();
    }

   private:
    SemaphoreHandle_t handle;
#if configSUPPORT_STATIC_ALLOCATION > 0
    StaticSemaphore_t buffer;
#endif
};


namespace os_basic {

    class MutexBase {
       protected:
        SemaphoreHandle_t _handle = nullptr;

        MutexBase() = default;

       public:
        bool lock(TickType_t timeout = portMAX_DELAY) {
            return xSemaphoreTake(_handle, timeout) == pdPASS;
        }


        bool try_lock() {
            return lock(0);
        }


        /**
         * @brief 释放互斥锁
         *
         * 释放互斥锁应该总是成功的，除非互斥锁并没有被 take。
         * 如果有更高优先级的任务正在等待互斥锁，调用这个函数会触发上下文切换。
         *
         * @return true
         * @return false
         */
        bool unlock() {
            return xSemaphoreGive(_handle) == pdPASS;
        }
        
        _MAKE__OBJECT__NONCOPYABLE(MutexBase);
    };


    class MutexScope {
        MutexBase &_m;

        public:
        MutexScope(MutexBase &m) : _m(m){
            _m.lock();
        }

        ~MutexScope() {
            _m.unlock();
        }
    };

#if configSUPPORT_STATIC_ALLOCATION > 0

    class StaticMutex : public MutexBase {
        protected:
        StaticSemaphore_t _buffer;

        public:
        bool create() {
            _handle = xSemaphoreCreateMutexStatic(&_buffer);
            
            return true;
        }
    };

#endif

    class DynamicMutex : public MutexBase {
        public:
        bool create() {
            _handle = xSemaphoreCreateMutex();
            
            if(_handle == NULL) {
                return false;
            }

            return true;
        }
    };
}  // namespace os_basic
